package cheme.ProcessEditor.DirectEdit;

import java.text.MessageFormat;

import org.eclipse.jface.util.Assert;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.List;

public class ListCellEditor extends CellEditor
{
	/**
     * The list of items to present in the combo box.
     */
    private String[] items;

    /**
     * The zero-based index of the selected item.
     */
    int selection;

    /**
     * The custom combo box control.
     */
    List list;
    
    /**
     * Default ListCellEditor style
     */
    private static final int defaultStyle = SWT.SINGLE;
    
    /**
     * Creates a new cell editor with no control and no set of choices.
     * Initially, the cell editor has no cell validator.
     * 
     * @see CellEditor#setStyle
     * @see CellEditor#create
     * @see ListCellEditor#setItems
     * @see CellEditor#dispose
     */
    public ListCellEditor()
    {
        setStyle(defaultStyle);
    }
    
    /**
	 * Creates a new cell editor with a combo containing the given list of
	 * choices and parented under the given control. The cell editor value is
	 * the zero-based index of the selected item. Initially, the cell editor has
	 * no cell validator and the first item in the list is selected.
	 * 
	 * @param parent the parent control
	 * @param items the list of strings for the combo box
	 */
    public ListCellEditor(Composite parent, String[] items)
    {
        this(parent, items, defaultStyle);
    }
    
    /**
	 * Creates a new cell editor with a combo containing the given list of
	 * choices and parented under the given control. The cell editor value is
	 * the zero-based index of the selected item. Initially, the cell editor has
	 * no cell validator and the first item in the list is selected.
	 * 
	 * @param parent the parent control
	 * @param items the list of strings for the combo box
	 * @param style the style bits
	 */
    public ListCellEditor(Composite parent, String[] items, int style)
    {
        super(parent, style);
        setItems(items);
    }
    
    /**
     * Returns the list of choices for the combo box
     *
     * @return the list of choices for the combo box
     */
    public String[] getItems()
	{
		return items;
	}

    /**
     * Sets the list of choices for the combo box
     *
     * @param items the list of choices for the combo box
     */
    public void setItems(String[] items)
	{
		Assert.isNotNull(items);
		this.items = items;
		populateListItems();
	}
    
    /**
	 * Updates the list of choices for the combo box for the current control.
	 */
    private void populateListItems()
	{
		if(list != null && items != null)
		{
			list.removeAll();
			for(int i = 0; i < items.length; i++)
			{
				list.add(items[i], i);
			}

//			list.setSize(width, height);
			
			setValueValid(true);
			selection = 0;
			
		}
	}
    
	@Override
	/* (non-Javadoc)
     * Method declared on CellEditor.
     */
    protected Control createControl(Composite parent) {

		list = new List(parent, getStyle());
		list.setFont(parent.getFont());

		list.addKeyListener(new KeyAdapter()
		{
			// hook key pressed - see PR 14201
			public void keyPressed(KeyEvent e)
			{
				keyReleaseOccured(e);
			}
		});

		list.addSelectionListener(new SelectionAdapter()
		{
			public void widgetDefaultSelected(SelectionEvent event)
			{
				applyEditorValueAndDeactivate();
			}

			public void widgetSelected(SelectionEvent event)
			{
				selection = list.getSelectionIndex();
			}
		});

		list.addTraverseListener(new TraverseListener()
		{
			public void keyTraversed(TraverseEvent e)
			{
				if(e.detail == SWT.TRAVERSE_ESCAPE || e.detail == SWT.TRAVERSE_RETURN)
				{
					e.doit = false;
				}
			}
		});

		list.addFocusListener(new FocusAdapter()
		{
			public void focusLost(FocusEvent e)
			{
				ListCellEditor.this.focusLost();
			}
		});
		
        return list;
    }
	
	/**
     * Applies the currently selected value and deactiavates the cell editor
     */
    void applyEditorValueAndDeactivate()
	{
		// must set the selection before getting value
		selection = list.getSelectionIndex();
		Object newValue = doGetValue();
		markDirty();
		boolean isValid = isCorrect(newValue);
		setValueValid(isValid);

		if(!isValid)
		{
			// Only format if the 'index' is valid
			if(items.length > 0 && selection >= 0 && selection < items.length)
			{
				// try to insert the current value into the error message.
				setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { items[selection] }));
			}
			else
			{
				// Since we don't have a valid index, do what we can... not much.
				setErrorMessage(MessageFormat.format(getErrorMessage(), new Object[] { "No Selection" }));
			}
		}

        fireApplyEditorValue();
        deactivate();
    }
    
    /**
	 * The <code>ListCellEditor</code> implementation of this
	 * <code>CellEditor</code> framework method returns the zero-based index
	 * of the current selection.
	 * 
	 * @return the zero-based index of the current selection wrapped as an
	 *         <code>Integer</code>
	 */
	protected Object doGetValue()
	{
		return new Integer(selection);
	}

	/*
	 * (non-Javadoc) Method declared on CellEditor.
	 */
	protected void doSetFocus()
	{
		list.setFocus();
	}

//    /**
//	 * The <code>ListCellEditor</code> implementation of this
//	 * <code>CellEditor</code> framework method sets the minimum width of the
//	 * cell. The minimum width is 10 characters if <code>list</code> is
//	 * not <code>null</code> or <code>disposed</code> eles it is 60 pixels
//	 * to make sure the arrow button and some text is visible. The list of
//	 * CCombo will be wide enough to show its longest item.
//	 */
//	public LayoutData getLayoutData()
//	{
//		LayoutData layoutData = super.getLayoutData();
//		
//		if((list == null) || list.isDisposed())
//		{
//			layoutData.minimumWidth = 60;
//		}
//		else
//		{
//			// make the comboBox 10 characters wide
//			GC gc = new GC(list);
//			layoutData.minimumWidth = (gc.getFontMetrics().getAverageCharWidth() * 10) + 10;
//			gc.dispose();
//		}
//		
//		return layoutData;
//	}

    /**
	 * The <code>ListCellEditor</code> implementation of this
	 * <code>CellEditor</code> framework method accepts a zero-based index of
	 * a selection.
	 * 
	 * @param value the zero-based index of the selection wrapped as an <code>Integer</code>
	 */
	protected void doSetValue(Object value)
	{
		Assert.isTrue(list != null && (value instanceof Integer));
		selection = ((Integer)value).intValue();
		list.select(selection);
	}

	/*
	 *  (non-Javadoc)
	 * @see org.eclipse.jface.viewers.CellEditor#focusLost()
	 */
	protected void focusLost()
	{
		if(isActivated())
		{
			applyEditorValueAndDeactivate();
		}
	}

	/*
	 *  (non-Javadoc)
	 * @see org.eclipse.jface.viewers.CellEditor#keyReleaseOccured(org.eclipse.swt.events.KeyEvent)
	 */
	protected void keyReleaseOccured(KeyEvent keyEvent)
	{
		if(keyEvent.character == '\u001b')
		{ // Escape character
			fireCancelEditor();
		}
		else if(keyEvent.character == '\t')
		{ // tab key
			applyEditorValueAndDeactivate();
		}
	}
	
	@Override
	public List getControl()
	{
		return (List)super.getControl();
	}
}
